<template>
	<view
	class="yb-popup yb-flex"
	:class="{'yb-justify-center': direction == 'center', 'yb-align-center': direction == 'center'}"
	:style="{position: optionsSync.position}" v-if="isShow">
		<view class="yb-mask yb-flex" :class="maskClass" :style="maskStyle" ref="ybMask" @tap="onMaskClick" v-if="maskSync.show" @touchmove.stop.prevent></view>
		<view class="yb-popup-content yb-flex" :class="popupClass" ref="ybPopupContent" :style="popupStyle" @touchmove.stop.prevent>
			<slot></slot>
		</view>
	</view>
</template>

<script>
	import Util from '../../js_sdk/util.js'
	import ComponentMixin from '../../js_sdk/componentMixin.js'
	// #ifdef APP-NVUE
	const Binding = uni.requireNativePlugin('bindingx')
	const dom = uni.requireNativePlugin('dom')
	// #endif
	export default {
		mixins: [ComponentMixin],
		props: {
			direction: {
				type: String,
				default: 'bottom'
			},
			duration : {
				type: Number,
				default: 300
			},
			//是否显示，支持.sync
			visible: {
				type: Boolean,
				default: false
			},
			options: {
				type: Object,
				default () {
					return new Object
				}
			}
		},
		data () {
			return {
				isShow: false,
				showState: false,
				maskClass: '',
				popupClass: '',
				windowWidth: 0,
				windowHeight: 0,
				popup_binding: null
			}
		},
		computed: {
			utils () {
				return Util
			},
			optionsSync () {
				return Object.assign({}, {
					mask: {},
					position: 'fixed',
					popout: 'fade'
				}, this.options)
			},
			maskSync () {
				return Object.assign({}, {
					show: true,
					color: 'rgba(0,0,0,.5)',
					click: true
				}, Util.typeof(this.optionsSync.mask) == 'Object' ? this.optionsSync.mask : Util.typeof(this.optionsSync.mask) == 'Boolean' ? {show: this.optionsSync.mask} : {})
			},
			maskStyle () {
				return this.filterStyle(
					// #ifdef APP-NVUE
					{
						opacity: this.showState ? 1 : 0,
						'background-color': this.maskSync.color
					}
					// #endif
					// #ifndef APP-NVUE
					{
						'background-color': this.maskSync.color,
						'animation-duration': this.duration + 'ms'
					}
					// #endif
				)
			},
			popupStyle () {
				return this.filterStyle(
					// #ifdef APP-NVUE
					!this.showState ? this.direction == 'top' ? {
						position: 'absolute',
						bottom: this.windowHeight + 'px',
						left: 0,
						right: 0
					} : this.direction == 'left' ? {
						position: 'absolute',
						bottom: 0,
						right: this.windowWidth + 'px',
						top: 0
					} : this.direction == 'right' ? {
						position: 'absolute',
						bottom: 0,
						left: this.windowWidth + 'px',
						top: 0
					} : this.direction == 'center' ? {} : {
						position: 'absolute',
						top: this.windowHeight + 'px',
						left: 0,
						right: 0
					} : Object.assign({}, {
						opacity: 1,
						transform: 'translate(0,0) scale(1)'
					}, this.direction == 'top' ? {
						position: 'absolute',
						top: 0,
						left: 0,
						right: 0
					} : this.direction == 'left' ? {
						position: 'absolute',
						top: 0,
						left: 0,
						bottom: 0
					} : this.direction == 'right' ? {
						position: 'absolute',
						top: 0,
						right: 0,
						bottom: 0
					} : this.direction == 'center' ? {} : {
						position: 'absolute',
						left: 0,
						right: 0,
						bottom: 0
					})
					// #endif
					// #ifndef APP-NVUE
					Object.assign({}, {
						'animation-duration': this.duration + 'ms'
					}, this.direction == 'top' ? {
						position: 'absolute',
						top: 0,
						left: 0,
						right: 0,
						transform: 'translateY(-100%)'
					} : this.direction == 'left' ? {
						position: 'absolute',
						bottom: 0,
						left: 0,
						top: 0,
						transform: 'translateX(-100%)'
					} : this.direction == 'right' ? {
						position: 'absolute',
						bottom: 0,
						right: 0,
						top: 0,
						transform: 'translateX(100%)'
					} : this.direction == 'center' ? {} : {
						position: 'absolute',
						bottom: 0,
						right: 0,
						left: 0,
						transform: 'translateY(100%)'
					}) 
					// #endif
				)
			}
		},
		mounted () {
			// #ifdef APP-NVUE
			uni.getSystemInfo({
				success: (res) => {
					this.windowWidth = res.windowWidth
					this.windowHeight = res.windowHeight
				}
			})
			// #endif
			this.isShow = this.visible
			this.$nextTick(function () {
				if ( this.isShow ) {
					this.show()
				}
			})
		},
		beforeDestroy() {
			// #ifdef APP-NVUE
			if ( this.popup_binding ) {
				Binding.unbind({
					token: this.popup_binding.token,
					eventType: 'timing'
				})
				this.popup_binding = null
			}
			// #endif
			// #ifndef APP-NVUE
			if ( this.popupTimer ) {
				clearTimeout(this.popupTimer)
				this.popupTimer = null
			}
			// #endif
		},
		methods: {
			show () {
				// #ifdef APP-NVUE
				this.getSize().then(size => {
					let popup = Util.getEl(this.$refs.ybPopupContent);
					let props = []
					if ( this.maskSync.show ) {
						let mask = Util.getEl(this.$refs.ybMask);
						props.push({
					        element: mask,
					        property: 'opacity',
					        expression: `linear(t, 0, 1, ${this.duration})`
					    })
					}
					props.push({
					    element: popup,
					    property: this.getProperty(),
					    expression: this.getShowExpression(size)
					})
					props.push({
					    element: popup,
					    property: 'opacity',
					    expression: `linear(t, 0, 1, ${this.duration})`
					})
					this.popup_binding = Binding.bind({
					    eventType: 'timing',
						exitExpression: 't>' + this.duration,
					    props: props
					}, (e) => {
						if ( e.state == 'exit' && e.t >= this.duration ) {
							if ( this.popup_binding ) {
								Binding.unbind({
									token: this.popup_binding.token,
									eventType: 'timing'
								})
								this.popup_binding = null
								this.showState = true
								this.$emit('show')
								this.$emit('update:visible', true)
							}
						}
					})
				})
				// #endif
				// #ifndef APP-NVUE
				this.popupClass = `yb-popup-${this.direction}-show`
				this.maskClass = 'yb-mask-show'
				this.popupTimer = setTimeout(() => {
					this.$emit('show')
					this.$emit('update:visible', true)
				}, this.duration)
				// #endif
			},
			hide () {
				// #ifdef APP-NVUE
				this.getSize().then(size => {
					let popup = Util.getEl(this.$refs.ybPopupContent);
					let props = []
					if ( this.maskSync.show ) {
						let mask = Util.getEl(this.$refs.ybMask);
						props.push({
						    element: mask,
						    property: 'opacity',
						    expression: `linear(t, 1, -1, ${this.duration})`
						})
					}
					if ( this.optionsSync.popout == 'auto' ) {
						props.push({
							element: popup,
							property: this.getProperty(),
							expression: this.getHideExpression(size)
						})
					}
					props.push({
					    element: popup,
					    property: 'opacity',
					    expression: `linear(t, 1, -1, ${this.duration})`
					})
					this.popup_binding = Binding.bind({
					    eventType: 'timing',
						exitExpression: 't>' + this.duration,
					    props: props
					}, (e) => {
						if ( e.state == 'exit' && e.t >= this.duration ) {
							if ( this.popup_binding ) {
								Binding.unbind({
									token: this.popup_binding.token,
									eventType: 'timing'
								})
								this.popup_binding = null
								this.showState = false
								this.$emit('hide')
								this.$emit('update:visible', false)
								this.isShow = false
							}
						}
					})
				})
				// #endif
				// #ifndef APP-NVUE
				this.popupClass = this.optionsSync.popout == 'auto' ? `yb-popup-${this.direction}-hide` : 'yb-popup-fade-hide'
				this.maskClass = 'yb-mask-hide'
				this.popupTimer = setTimeout(() => {
					this.$emit('hide')
					this.$emit('update:visible', false)
					this.isShow = false
					this.popupClass = ''
					this.maskClass = ''
				}, this.duration)
				// #endif
			},
			onMaskClick () {
				if ( this.maskSync.click ) {
					this.hide()
				}
			},
			getProperty () {
				if ( this.direction == 'left' || this.direction == 'right' ) {
					return 'transform.translateX'
				} else if ( this.direction == 'center' ) {
					return 'transform.scale'
				} else {
					return 'transform.translateY'
				}
			},
			getShowExpression (size) {
				if ( this.direction == 'top' ) {
					return `linear(t, 0, ${size.height}, ${this.duration})`
				} else if ( this.direction == 'left' ) {
					return `linear(t, 0, ${size.width}, ${this.duration})`
				} else if ( this.direction == 'right' ) {
					return `linear(t, 0, -${size.width}, ${this.duration})`
				} else if ( this.direction == 'center' ) {
					return `linear(t, 0, 1, ${this.duration})`
				}  else {
					return `linear(t, 0, -${size.height}, ${this.duration})`
				}
			},
			getHideExpression (size) {
				if ( this.direction == 'top' ) {
					return `linear(t, 0, -${size.height}, ${this.duration})`
				} else if ( this.direction == 'left' ) {
					return `linear(t, 0, -${size.width}, ${this.duration})`
				} else if ( this.direction == 'right' ) {
					return `linear(t, 0, ${size.width}, ${this.duration})`
				} else if ( this.direction == 'center' ) {
					return `linear(t, 1, -1, ${this.duration})`
				} else {
					return `linear(t, 0, ${size.height}, ${this.duration})`
				}
			},
			getSize () {
				return new Promise(resolve => {
					setTimeout(() => {
						// #ifdef APP-NVUE
							dom.getComponentRect(this.$refs.ybPopupContent, res => {
								resolve({
									width: res.size.width,
									height: res.size.height
								})
							})
						// #endif
						// #ifndef APP-NVUE
						uni.createSelectorQuery().in(this).select('.yb-popup-content').boundingClientRect(data => {
							resolve({
								width: data.width,
								height: data.height
							})
						}).exec();
						// #endif
					}, 50)
				})
			}
		},
		watch: {
			visible (newVal) {
				if ( newVal && !this.isShow ) {
					this.isShow = true
					this.$nextTick(function () {
						this.show()
					})
				} else if ( !newVal && this.isShow ) {
					this.hide()
				}
			}
		}
	}
</script>

<style scoped>
	/* #ifndef APP-NVUE */
	@keyframes opacity_show {
		from {
			opacity: 0;
		}
		to {
			opacity: 1;
		}
	}
	@keyframes opacity_hide {
		from {
			opacity: 1;
		}
		to {
			opacity: 0;
		}
	}
	@keyframes bottom_show {
		from {
			transform: translateY(100%);
			opacity: 0;
		}
		to {
			transform: translateY(0);
			opacity: 1;
		}
	}
	@keyframes bottom_hide {
		from {
			transform: translateY(0);
			opacity: 1;
		}
		to {
			transform: translateY(100%);
			opacity: 0;
		}
	}
	@keyframes top_show {
		from {
			transform: translateY(-100%);
			opacity: 0;
		}
		to {
			transform: translateY(0);
			opacity: 1;
		}
	}
	@keyframes top_hide {
		from {
			transform: translateY(0);
			opacity: 1;
		}
		to {
			transform: translateY(-100%);
			opacity: 0;
		}
	}
	@keyframes left_show {
		from {
			transform: translateX(-100%);
			opacity: 0;
		}
		to {
			transform: translateX(0);
			opacity: 1;
		}
	}
	@keyframes left_hide {
		from {
			transform: translateX(0);
			opacity: 1;
		}
		to {
			transform: translateX(-100%);
			opacity: 0;
		}
	}
	@keyframes right_show {
		from {
			transform: translateX(100%);
			opacity: 0;
		}
		to {
			transform: translateX(0);
			opacity: 1;
		}
	}
	@keyframes right_hide {
		from {
			transform: translateX(0);
			opacity: 1;
		}
		to {
			transform: translateX(100%);
			opacity: 0;
		}
	}
	@keyframes center_show {
		from {
			transform: scale(0);
			opacity: 0;
		}
		to {
			transform: scale(1);
			opacity: 1;
		}
	}
	@keyframes center_hide {
		from {
			transform: scale(1);
			opacity: 1;
		}
		to {
			transform: scale(0);
			opacity: 0;
		}
	}
	/* #endif */
	.yb-popup {
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		/* #ifndef APP-NVUE */
		pointer-events: none;
		z-index: 9;
		/* #endif */
	}
	.yb-popup-content {
		/* #ifndef APP-NVUE */
		pointer-events: auto;
		/* #endif */
		opacity: 0;
	}
	.yb-mask {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		opacity: 0;
		/* #ifndef APP-NVUE */
		pointer-events: auto;
		/* #endif */
	}
	/* #ifndef APP-NVUE */
	.yb-mask-show {
		animation-name: opacity_show;
		animation-fill-mode: forwards;
	}
	.yb-mask-hide {
		animation-name: opacity_hide;
		animation-fill-mode: forwards;
	}
	.yb-popup-bottom-show {
		animation-name: bottom_show;
		animation-fill-mode: forwards;
	}
	.yb-popup-bottom-hide {
		animation-name: bottom_hide;
		animation-fill-mode: forwards;
	}
	.yb-popup-top-show {
		animation-name: top_show;
		animation-fill-mode: forwards;
	}
	.yb-popup-top-hide {
		animation-name: top_hide;
		animation-fill-mode: forwards;
	}
	.yb-popup-left-show {
		animation-name: left_show;
		animation-fill-mode: forwards;
	}
	.yb-popup-left-hide {
		animation-name: left_hide;
		animation-fill-mode: forwards;
	}
	.yb-popup-right-show {
		animation-name: right_show;
		animation-fill-mode: forwards;
	}
	.yb-popup-right-hide {
		animation-name: right_hide;
		animation-fill-mode: forwards;
	}
	.yb-popup-center-show {
		animation-name: center_show;
		animation-fill-mode: forwards;
	}
	.yb-popup-center-hide {
		animation-name: center_hide;
		animation-fill-mode: forwards;
	}
	.yb-popup-fade-hide {
		transform: translate(0) scale(1)!important;
		animation-name: opacity_hide;
		animation-fill-mode: forwards;
	}
	/* #endif */
</style>
